<?php
/**
 * app店铺肤质检测的数据管理
 *
 * Author: lyun
 * Date: 2018/3/27
 * Created by Panxsoft.
 */

namespace App\Http\Controllers\App;

use App\Http\Controllers\ApiController;
use App\Http\Requests\App\SkinRecord\SendSkinRecordReportRequest;
use App\Http\Requests\App\SkinRecord\SendTemplateNoticeRequest;
use App\Models\Customer\DeviceAccount;
use App\Models\OpenWechat\Authorizer;
use App\Models\OpenWechat\WechatTemplateNotice;
use App\Models\OpenWechat\WechatUser;
use App\Models\Store\StorePivotWechatUser;
use App\Services\Mailer\App\SkinRecordReportMail;
use App\Services\OpenWechat\AppFactory;
use App\Services\OpenWechat\CustomerTemplateNotice;
use App\Services\OpenWechat\TemplateNotice;
use App\Services\Presenters\HmSkinData;
use App\Services\Presenters\WaxSkinData;
use App\Services\Presenters\Wechat\TemplateNotice\SkinRecordNoticePresenter;
use App\Services\Repositories\SkinRecord\SkinRecordBonusRepository;
use App\Services\Repositories\SkinRecord\SkinRecordRepository;
use App\Services\Repositories\WechatTemplateNoticeRepository;
use App\Services\Utils\Guard;
use App\Http\Requests\App\Store\SkinRecordStoreRequest;
use App\Models\Panx\SkinDetector;
use App\Models\Store\CamSkinRecord;
use App\Models\Store\HmSkinRecord;
use App\Models\Store\SkinRecord;
use App\Models\Store\WaxSkinRecord;
use App\Services\Presenters\SkinRecordPresenter;
use App\Services\Utils\Transaction;

class SkinRecordController extends ApiController
{
    const ROUTE_NAME = [
        'store' => 'api.app.skin.record.store',
    ];

    /**
     * Store a newly created resource in storage.
     * @test
     *
     * @param  SkinRecordStoreRequest $request
     * @return \Illuminate\Http\Response
     * @throws \Exception
     */
    public function store(SkinRecordStoreRequest $request)
    {
        $customer_id = Guard::deviceAccount()->customer_id;

        /**
         * @var SkinRecord $skin_record
         * @var HmSkinRecord|WaxSkinRecord $type_skin_record
         */
        list($skin_record, $type_skin_record) = $this->transactStoreSkinRecord($request);

        $skin_record_id = $skin_record->id;

        $record_detail = $this->assembleTypeSkinRecordDetail($request->skin_detector_id, $type_skin_record, $customer_id);

        if (config('app.env') === 'production') { // 生产状态发送
            $this->checkSendSkinInfoNotice($request->no_send_skin_info, $skin_record);

            // 发红包、模板消息
            (new SkinRecordBonusRepository())->recordSkinRecordBonus($skin_record);
        }

        return $this->response(compact('skin_record_id', 'type_skin_record', 'record_detail'));
    }

    /**
     * @param SendTemplateNoticeRequest $request
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function sendTemplateNotice(SendTemplateNoticeRequest $request)
    {
        $skin_record = SkinRecord::find($request->skin_record_id);
        $this->checkItemExist($skin_record, trans('wechat.skin_record'));

        $res = $this->checkAllDoneSendTemplateNotice($skin_record);

        $this->checkIsTrue(
            ($res['errcode'] ?? null) === 0,
            $res['errmsg'] ?? trans('checker.check_operate_success', ['tip' => 'send-template-notice'])
        );

        return $this->response(compact('res'));
    }

    /**
     * @param SendSkinRecordReportRequest $request
     *
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function sendEmailReport(SendSkinRecordReportRequest $request)
    {
        $skin_record = SkinRecord::find($request->skin_record_id);
            $this->checkItemExist($skin_record, trans('wechat.skin_record'));
            $this->checkIsTrue($skin_record->wechatUser, trans('app.wechat_user_not_found'));

        $url = url(sprintf(WechatUser::WX_SKIN_REPORT_URL_FORMAT, http_build_query([
            'openid'           => $skin_record->wechatUser->openid,
            'appid'            => $skin_record->wechatUser->authorizer->authorizer_appid ?? 'no_author', // 没有 公众号但必须有值，否则前端无法跳转
            'customer_id'      => $skin_record->wechatUser->customer_id ?: null, // 如果是 0 表示有公众号，不显示 customer_id 字段
            'skin_detector_id' => $skin_record->skin_detector_id,
            'mode'             => 'pc',
        ])));

        SkinRecordReportMail::send($request->email, $url);

        return $this->response(compact('url'));
    }

    /**
     * @param SkinRecordStoreRequest $request
     * @param SkinRecord $skinRecord
     * @return WaxSkinRecord
     * @throws \Exception
     */
    private function storeSkinRecordWax(SkinRecordStoreRequest $request, SkinRecord $skinRecord)
    {
        $skin_record_wax = $this->assembleSkinRecordWax($request, $skinRecord);

        $wax_skin_record = WaxSkinRecord::checkHasSkinRecord($skin_record_wax);
        if ($wax_skin_record) {
            // 更新现有的检测项目
            $wax_skin_record->update($skin_record_wax);
        } else {
            // 添加其他检测项目
            $wax_skin_record = (new WaxSkinRecord)->create($skin_record_wax);
        }

        return $wax_skin_record;
    }

    /**
     * @param SkinRecordStoreRequest $request
     * @param SkinRecord $skin_record
     * @return CamSkinRecord
     * @throws \Exception
     */
    private function storeSkinRecordCamera(SkinRecordStoreRequest $request, SkinRecord $skin_record)
    {
        $skin_record_camera = $this->assembleSkinRecordCamera($request, $skin_record);

        $cam_skin_record = CamSkinRecord::checkHasSkinRecord($skin_record_camera);
        if ($cam_skin_record) {
            // 更新现有的检测项目
            $cam_skin_record->update($skin_record_camera);
        } else {
            // 新增记录
            $cam_skin_record = CamSkinRecord::create($skin_record_camera);
        }

        return $cam_skin_record;
    }

    /**
     * @param SkinRecordStoreRequest $request
     * @param SkinRecord $skin_record
     * @return HmSkinRecord
     */
    private function storeSkinRecordHm(SkinRecordStoreRequest $request, SkinRecord $skin_record)
    {
        $skin_record_hm = $this->assembleSkinRecordHm($request, $skin_record);

        $hm_skin_record = HmSkinRecord::checkHasSkinRecord($skin_record_hm);
        if ($hm_skin_record) {
            // 更新现有的检测项目
            $hm_skin_record->update($skin_record_hm);
        } else {
            // 添加其他检测项目
            $hm_skin_record = HmSkinRecord::create($skin_record_hm);
        }

        return $hm_skin_record;
    }

    /**
     * @param SkinRecordStoreRequest $request
     * @param SkinRecord $skin_record
     * @return array
     */
    private function assembleSkinRecordWax(SkinRecordStoreRequest $request, SkinRecord $skin_record)
    {
        $record_data = [
            'skin_record_id'      => $skin_record->id,
            'itemsid'             => $request->itemsid,
            'itemsname'           => $request->itemsname,
            'value'               => $request->value,
            'type'                => $request->type,
            'levelsort'           => $request->levelsort,
            'wechat_user_id'      => $request->wechat_user_id,
            'origin_img'          => $request->origin_img,
            'analyse_img'         => $request->analyse_img,
        ];

        return $record_data;
    }

    /**
     * @param SkinRecordStoreRequest $request
     * @param SkinRecord $skin_record
     * @return array
     */
    private function assembleSkinRecordCamera(SkinRecordStoreRequest $request, SkinRecord $skin_record)
    {
        $record_data = [
            'skin_record_id' => $skin_record->id,
            'dark_circle'    => $request->dark_circle,
            'stain'          => $request->stain,
            'acne'           => $request->acne,
            'health'         => $request->health,
            'wechat_user_id' => $request->wechat_user_id,
        ];

        return $record_data;
    }

    /**
     * @param SkinRecordStoreRequest $request
     * @param SkinRecord $skin_record
     * @return array
     */
    private function assembleSkinRecordHm(SkinRecordStoreRequest $request, SkinRecord $skin_record)
    {
        $record_data = [
            'skin_record_id' => $skin_record->id,
            'position'       => $request->position,
            'flex'           => $request->flex,
            'oil'            => $request->oil,
            'water'          => $request->water,
            'age'            => $request->age,
            'wechat_user_id' => $request->wechat_user_id,
        ];

        return $record_data;
    }

    /**
     * @param SkinRecordStoreRequest $request
     *
     * @return SkinRecord|\Illuminate\Database\Eloquent\Model
     */
    private function firstOrCreateSkinRecord(SkinRecordStoreRequest $request): SkinRecord
    {
        /** @var DeviceAccount $dev_acnt */
        $dev_acnt = Guard::deviceAccount();

        $store = $dev_acnt->store;

        // 记录store_pivot_wechat_user表的信息
        (new StorePivotWechatUser)->firstOrCreate([
            'store_id'       => $store->id,
            'wechat_user_id' => $request->wechat_user_id,
        ]);

        return (new SkinRecord)->firstOrCreate([
            'id' => $request->skin_record_id
        ], [
            'store_id'          => $dev_acnt->store_id,
            'wechat_user_id'    => $request->wechat_user_id,
            'skin_detector_id'  => $request->skin_detector_id,
            'device_account_id' => $dev_acnt->id,
            'store_admin_id'    => $request->store_admin_id ?: 0,
        ]);
    }

    /**
     * @param SkinRecordStoreRequest $request
     * @param SkinRecord $skin_record
     * @return CamSkinRecord|HmSkinRecord|WaxSkinRecord
     * @throws \Exception
     */
    private function storeTypeSkinRecord(SkinRecordStoreRequest $request,
                                         SkinRecord $skin_record)
    {
        // 根据不同的肤质检测仪来保存数据 1：摄像头拍摄检测。2：唯丝普接触图像检测仪。 3：汇美接触式检测仪
        switch($request->skin_detector_id)
        {
            case SkinDetector::ID_WAX:
                $type_skin_record = $this->storeSkinRecordWax($request, $skin_record);
                break;
            case SkinDetector::ID_CAMERA:
                $type_skin_record = $this->storeSkinRecordCamera($request, $skin_record);
                break;
            case SkinDetector::ID_HM:
                $type_skin_record = $this->storeSkinRecordHm($request, $skin_record);
                break;
            default:
                $type_skin_record = null;
                $this->checkIsTrue(false, trans('app.skin_detector_type_error'));
        }

        return $type_skin_record;
    }

    /**
     * @param string $skin_detector_id
     * @param CamSkinRecord|HmSkinRecord|WaxSkinRecord $type_skin_record
     * @param $customer_id
     * @return HmSkinRecord|WaxSkinRecord|array|null
     */
    private function assembleTypeSkinRecordDetail($skin_detector_id, $type_skin_record, $customer_id)
    {
        switch($skin_detector_id)
        {
            case SkinDetector::ID_WAX:
                $wax_suggests = WaxSkinData::getWaxSkinSuggest($customer_id);
                return SkinRecordPresenter::assembleDetailWaxSkinRecordByCustom($type_skin_record, $wax_suggests);
            case SkinDetector::ID_CAMERA:
                return SkinRecordPresenter::assembleDetailCamSkinRecord($type_skin_record);
            case SkinDetector::ID_HM:
                $hm_suggests = HmSkinData::getHmSkinSuggest($customer_id);
                return SkinRecordPresenter::assembleDetailHmSkinRecordByCustom($type_skin_record, $hm_suggests);
            default:
                return null;
        }

    }

    /**
     * @param SkinRecordStoreRequest $request
     * @return bool|array
     * @throws \Exception
     */
    private function transactStoreSkinRecord(SkinRecordStoreRequest $request)
    {
        return Transaction::handle(function () use ($request) {
            $skin_record = $this->firstOrCreateSkinRecord($request);

            $type_skin_record = $this->storeTypeSkinRecord($request, $skin_record);

            return [$skin_record, $type_skin_record];
        });
    }

    /**
     * 完成所有测试发微信模板消息通知查看结果
     *
     * @param SkinRecord $skin_record
     *
     * @return array|null
     * @throws \Exception
     */
    private function checkAllDoneSendTemplateNotice(SkinRecord $skin_record)
    {
        $done = SkinRecordRepository::isAllSubSkinRecordsDone($skin_record);
        if (! $done) {
            return null;
        }

        $author = $skin_record->store->customer->authorizer ?? null;
        if (! $author) {
            return null;
        }

        $template_id = (new WechatTemplateNoticeRepository())
            ->getAuthorizerTemplateId($author, WechatTemplateNotice::ID_SHORT_SKIN_RESULT);
        if (! $template_id) {
            return null;
        }

        $notice = new TemplateNotice($author->authorizer_appid);
        $wechatUser = $skin_record->wechatUser;
        $url = $this->wechatSkinRecordDetailUrl($author, $wechatUser, $skin_record);

        $notice_data = $this->getNoticeData($author, $skin_record);

        $res = $notice->skinResultNotice(
            $wechatUser->openid, $template_id, $url, $notice_data
        );

        return $res;
    }

    /**
     * 微信肤质详情页面路由
     *
     * @param Authorizer $author
     * @param WechatUser $wechatUser
     * @param SkinRecord $skin_record
     *
     * @return string
     */
    private function wechatSkinRecordDetailUrl(Authorizer $author,
                                               WechatUser $wechatUser,
                                               SkinRecord $skin_record): string
    {
        $qs = http_build_query([
            'appid'            => $author->authorizer_appid,
            'openid'           => $wechatUser->openid,
            'skin_detector_id' => $skin_record->skin_detector_id,
        ]);

        return url(sprintf(WechatUser::WX_SKIN_REPORT_URL_FORMAT, $qs));
    }

    /**
     * @param Authorizer $authorizer
     * @param $skin_record
     *
     * @return array
     */
    public function getNoticeData(Authorizer $authorizer, SkinRecord $skin_record): array
    {
        $app = (new AppFactory())->authorizerApp($authorizer->authorizer_appid);

        if (CustomerTemplateNotice::isIndustryIt($app)) {
            $notice_data = $this->assembleITSkinResultNoticeData($skin_record);
        } else {
            $notice_data = $this->assembleSkinResultNoticeData($skin_record);
        }

        return $notice_data;
    }

    public function assembleSkinResultNoticeData(SkinRecord $skin_record): array
    {
        $wechatUser = $skin_record->wechatUser;
        $customer_id = Guard::deviceAccount()->customer_id;

        /**
         * @uses \App\Services\OpenWechat\TemplateNotice::skinResultNotice
         */
        return [
            'first'    => trans('wechat.test_results'),
            'keyword1' => $wechatUser->name ?: $wechatUser->nickname,
            'keyword2' => now()->toDateTimeString(),
            'remark'   => (new SkinRecordNoticePresenter)->assembleRemark($skin_record, $customer_id),
        ];
    }

    /**
     * IT行业模板消息
     *
     * @param SkinRecord $skin_record
     * @return array
     */
    public function assembleITSkinResultNoticeData(SkinRecord $skin_record): array
    {
        $customer_id = Guard::deviceAccount()->customer_id;
        //   {{first.DATA}}
        //    检测内容：{{keyword1.DATA}}
        //    检测结果：{{keyword2.DATA}}
        //    {{remark.DATA}}
        return [
            'first'    => trans('wechat.test_results'),
            'keyword1' => trans('wechat.skin_test'),
            'keyword2' => trans('wechat.detection_completed'),
            'remark'   => (new SkinRecordNoticePresenter)->assembleRemark($skin_record, $customer_id),
        ];
    }


    /**
     * @param int $not_send
     * @param SkinRecord $skin_record
     *
     * @return array|null
     * @throws \Exception
     */
    private function checkSendSkinInfoNotice(?int $not_send,
                                             SkinRecord $skin_record) :?array
    {
        if ($not_send === 1) {
            return null;
        }

        return $this->checkAllDoneSendTemplateNotice($skin_record);
    }

}
